package com.lemon.boot.common.config;

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.lemon.boot.common.interceptor.SecurityMethodInterceptor;
import com.lemon.boot.common.interceptor.SecurityNotAuthorizationInterceptor;
import com.lemon.boot.common.listener.ApplicationStartEventListener;
import com.lemon.boot.common.properties.FileConfigProperties;
import com.lemon.boot.common.properties.JwtConfigProperties;
import com.lemon.boot.common.service.RedisService;
import com.lemon.boot.common.utils.LocalDateUtil;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

/**
 * @author 李猛
 * @datetime 2024/2/28 18:59
 * @description 类对象
 */
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
    public JwtConfigProperties jwtConfigProperties;
    public FileConfigProperties fileConfigProperties;
    public ApplicationStartEventListener applicationStartEventListener;
    public RedisService redisService;

    public WebMvcConfiguration(JwtConfigProperties jwtConfigProperties,
                               FileConfigProperties fileConfigProperties,
                               ApplicationStartEventListener applicationStartEventListener,
                               RedisService redisService) {
        this.jwtConfigProperties = jwtConfigProperties;
        this.fileConfigProperties = fileConfigProperties;
        this.applicationStartEventListener = applicationStartEventListener;
        this.redisService = redisService;
    }

    /**
     * Security权限拦截器
     *
     * @return
     */
    @Bean
    public SecurityMethodInterceptor securityMethodInterceptor() {
        return new SecurityMethodInterceptor();
    }

    /**
     * Security不需要认证的拦截器
     *
     * @return
     */
    @Bean
    public SecurityNotAuthorizationInterceptor securityNotAuthorizationInterceptor() {
        return new SecurityNotAuthorizationInterceptor(redisService);
    }

    /**
     * 拦截
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //1.权限拦截器
        registry.addInterceptor(securityMethodInterceptor())
                .excludePathPatterns(jwtConfigProperties.getAllPassUriByArray())
                .excludePathPatterns(applicationStartEventListener.getNotAuthorizationPath());

        //2.不需要认证的拦截器
        registry.addInterceptor(securityNotAuthorizationInterceptor())
                .addPathPatterns(applicationStartEventListener.getNotAuthorizationPath());
    }

    /**
     * 解决跨域
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedHeaders("*")
                .maxAge(3600L)
                .allowCredentials(true) //允许凭证请求
                .allowedMethods(jwtConfigProperties.getAllowMethod());//允许方法
    }

    /**
     * 响应消息转换
     *
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
        SimpleModule simpleModule = new SimpleModule();

        //Long 类型数据转换
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);

        //日期类型转换-响应
        simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(LocalDateUtil.DATE_FORMATTER_4));
        simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer(LocalDateUtil.DATE_FORMATTER_5));
        simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer(LocalDateUtil.DATE_FORMATTER_6));

        //日期类型转换-请求
        simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(LocalDateUtil.DATE_FORMATTER_4));
        simpleModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(LocalDateUtil.DATE_FORMATTER_5));
        simpleModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(LocalDateUtil.DATE_FORMATTER_6));

        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(0, jackson2HttpMessageConverter);
    }

    /**
     * 读取文件
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(fileConfigProperties.getPathMatch())
                .addResourceLocations(fileConfigProperties.getFileResourceLocation());
    }

    /**
     * 增加GET请求参数中时间类型转换
     *
     * @param registry
     */
    @Override
    public void addFormatters(@NotNull FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setTimeFormatter(DatePattern.NORM_TIME_FORMATTER);
        registrar.setDateFormatter(DatePattern.NORM_DATE_FORMATTER);
        registrar.setDateTimeFormatter(DatePattern.NORM_DATETIME_FORMATTER);
        registrar.registerFormatters(registry);
    }
}
